#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <pthread.h>
#include <unistd.h>
#include <functional>
#include <ctime>
#include "blockqueue.hpp"
using namespace std;

typedef function<string()> task;

string PrintLog() {
    return "我是一个打印日志的任务，我正在努力的打印日志……";
}

string PlayMusic() {
    return "我是一个播放音乐的任务，我正在努力的播放音乐……";
}

string PlayVideo() {
    return "我是一个播放视频的任务，我正在努力的播放视频……";
}
string DownLoad() {
    return "我是一个下载任务，我正在努力的下载……";
}

vector<task> tasks;
vector<string> taskname = { "PrintLog", "PlayMusic", "PlayVideo", "DownLoad" };









template <class T>
struct ThreadData {
    ThreadData(const string& threadname, blockqueue<T>* bq)
        :_threadname(threadname)
        ,_bq(bq)
    {
    }
    string _threadname;
    blockqueue<T>* _bq;
};

void *productor(void* args) {
    ThreadData<task> *data = static_cast<ThreadData<task>*>(args);
    while (true) {
        int index = rand() % tasks.size();
        task t = tasks[index];
        usleep(1000);
        data->_bq->Push(t);
        cout << data->_threadname << "发送任务：" << taskname[index] << endl;

    }

    return nullptr;
}

void *consumer(void* args) {
    ThreadData<task> *data = static_cast<ThreadData<task>*>(args);
    while (true) {
        task t;
        data->_bq->Pop(&t);
        string t_r_val = t();
        usleep(1000);

        cout << "我是" << data->_threadname << ", " << t_r_val << endl;
        sleep(1);

    }
    return nullptr;
}



int main() {
    srand(time(nullptr) ^ getpid() ^ pthread_self());
    tasks.push_back(PrintLog);
    tasks.push_back(PlayMusic);
    tasks.push_back(PlayVideo);
    tasks.push_back(DownLoad);
    blockqueue<task> *bq = new blockqueue<task>;
    pthread_t p[2], c[3];

    // 生产者
    ThreadData<task> *data1 = new ThreadData<task>("producer1", bq);
    pthread_create(&p[0], nullptr, productor, data1);

    ThreadData<task> *data2 = new ThreadData<task>("producer2", bq);
    pthread_create(&p[1], nullptr, productor, data2);

    // 消费者
    ThreadData<task> *data3 = new ThreadData<task>("consumer1", bq);
    pthread_create(&c[0], nullptr, consumer, data3);

    ThreadData<task> *data4 = new ThreadData<task>("consumer2", bq);
    pthread_create(&c[1], nullptr, consumer, data4);

    ThreadData<task> *data5 = new ThreadData<task>("consumer3", bq);
    pthread_create(&c[2], nullptr, consumer, data5);


    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(c[2], nullptr);
    return 0;
}